package org.vsg.stock.basic.service.indicator.processor;

import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.vsg.stock.basic.service.indicator.shape.FocusLineEquation;
import org.vsg.stock.core.indicator.KLineStockIndicatorModel;
import org.vsg.stock.core.indicator.ZigIndicator;
import org.vsg.stock.core.indicator.coordinate.CoordinateContext;
import org.vsg.stock.core.indicator.coordinate.CoordinatePoint;
import org.vsg.stock.core.indicator.coordinate.OriginalDataPoint;
import org.vsg.stock.core.indicator.coordinate.Processor;
import org.vsg.stock.core.indicator.coordinate.ShapeEquation;
import org.vsg.stock.core.indicator.coordinate.origpoint.KLineLowOriginalDataPoint;
import org.vsg.stock.core.indicator.coordinate.shape.AbstractLineEquation;
import org.vsg.stock.core.indicator.kline.ZigIndicatorResultItem;
import org.vsg.stock.core.kline.DailyKLineStock;

public class HorizontalFocusLineProcessor implements Processor<DailyKLineStock> {

	private DecimalFormat df = new DecimalFormat("0.00");	
	
	@Override
	public List<ShapeEquation> process(CoordinateContext context,
			List<DailyKLineStock> dataList) {
		
		// --- 找出多个最高最低价共享 ---
		List<CoordinatePoint> troughPoints = findCoorPointsByTrough (dataList , context);
		
		List<CoordinatePoint> crestPoints = findCoorPointsByCrest(dataList , context);
			
		CoordinatePoint point1 = null;
		
		List<AbstractLineEquation> shapeEquationsList = new Vector<AbstractLineEquation>();
		
		List<CoordinatePoint> existPoint = new Vector<CoordinatePoint>();

		// --- add trough points ---
		for (int i = 0 ; i < troughPoints.size() ; i++) {
			point1 = troughPoints.get(i);

			if (existPoint.contains( point1 )) {
				continue;
			}

			// --- 不超过 1%的误差 ---
			List<CoordinatePoint> otherPoints = findAssoCoordinatePointsByRefPoints(point1 , context ,dataList);
			
			if ( otherPoints.size() > 1) {
				int count = 0;
				double bSum = 0;
				CoordinatePoint aPoint = null;
				for (int j = 0 ; j < otherPoints.size() ; j++) {
					aPoint = otherPoints.get(j);
					count++;
					bSum = bSum + aPoint.getYvalue();
					existPoint.add( aPoint );
					

				}
				double avgB = bSum /count;
			
				FocusLineEquation focusle = new FocusLineEquation();
				focusle.setCoefficientA((double)0);
				focusle.setCoefficientB(avgB);
				shapeEquationsList.add( focusle );

			
				// --- add different point list ---
				existPoint.add( point1 );
			}
		}	
		
		point1 = null;

		for (int i = 0 ; i < crestPoints.size() ; i++) {
			point1 = crestPoints.get(i);

			if (existPoint.contains( point1 )) {
				continue;
			}			
			
			// --- 不超过 1%的误差 ---
			List<CoordinatePoint> otherPoints = findAssoCoordinatePointsByRefPoints(point1 , context ,dataList);
			
			if ( otherPoints.size() > 1) {
				int count = 0;
				double bSum = 0;
				CoordinatePoint aPoint = null;
				for (int j = 0 ; j < otherPoints.size() ; j++) {
					aPoint = otherPoints.get(j);
					count++;
					bSum = bSum + aPoint.getYvalue();
					existPoint.add( aPoint );					
				}
				double avgB = bSum /count;
			
				FocusLineEquation focusle = new FocusLineEquation();
				focusle.setCoefficientA((double)0);
				focusle.setCoefficientB(avgB);
				shapeEquationsList.add( focusle );
				
				existPoint.add( point1 );				
			}
		}		
		
		// --- merge all line equation ----
		//List<ShapeEquation> result = mergeTopSameLine( shapeEquationsList );
		
		System.out.println("show size : " + shapeEquationsList.size());
				
		return null;
	}
	
	
	private List<CoordinatePoint> findAssoCoordinatePointsByRefPoints(
			CoordinatePoint point , CoordinateContext context,
			List<DailyKLineStock> dataList) {

		OriginalDataPoint odp = context.transformToOriginalDataPoint( point );		
		Date comparedDate = odp.getXvalue();
		double orginalPointPrice = context.getOriginPoint().getYvalue() ;
		double comparedPrice = odp.getYvalue() + orginalPointPrice;
		
		List<CoordinatePoint> allPoints = new Vector<CoordinatePoint>();

		// --- show kline list ---
		for (DailyKLineStock kline : dataList) {
			// --- 
			if (kline.getDate().equals( comparedDate)  ) {
				continue;
			}
			
			double lowPriceComparedRate = Math.abs(kline.getLow() - comparedPrice) / orginalPointPrice;
			// --- ---
			double highPriceComparedRate = Math.abs(kline.getHigh() - comparedPrice) / orginalPointPrice;
			
			boolean meetTarget = lowPriceComparedRate < 0.003 || highPriceComparedRate < 0.003;
			
			if ( meetTarget ) {
				// --- build the point ---
				OriginalDataPoint dataPoint = new KLineLowOriginalDataPoint(kline);
				CoordinatePoint refPoint = context.transformToCoordinatePoint(dataPoint);				
				
				allPoints.add( refPoint );
			}
		}
		
		return allPoints;
	}
	
	
	
	
	@SuppressWarnings("unchecked")
	private List<CoordinatePoint> findCoorPointsByTrough(List<DailyKLineStock> dataList, CoordinateContext context) {
		KLineStockIndicatorModel klineStkIndiModel = 
			new KLineStockIndicatorModel(dataList ,KLineStockIndicatorModel.KLinePosition.LOW);
		
		ZigIndicator zigInd = new ZigIndicator();
		// 过细,将无法分出波,过大找的波较少,对于价来说, 3-3.3为合适
		zigInd.setThreshold( (double)3.2 );
		zigInd.setIndicatorModel( klineStkIndiModel );

		// --- use one point value check ---
		Map<String, java.io.Serializable > resultMap  = zigInd.calculate();

		List<CoordinatePoint> points = new Vector<CoordinatePoint>();
		
		// --- 找出波谷 ---
		List<ZigIndicatorResultItem> troughs = (List<ZigIndicatorResultItem>) resultMap.get( ZigIndicator.ALL_TROUGH );		
		for (ZigIndicatorResultItem item : troughs) {
			DailyKLineStock kline = (DailyKLineStock)item.getAssoRef();
			OriginalDataPoint dataPoint = new KLineLowOriginalDataPoint(kline);
			CoordinatePoint refPoint = context.transformToCoordinatePoint(dataPoint);
			points.add(refPoint);
		}
		
		return points;
		
	}

	@SuppressWarnings("unchecked")
	private List<CoordinatePoint> findCoorPointsByCrest(List<DailyKLineStock> dataList, CoordinateContext context) {
		KLineStockIndicatorModel klineStkIndiModel = 
			new KLineStockIndicatorModel(dataList ,KLineStockIndicatorModel.KLinePosition.HIGH);
		
		ZigIndicator zigInd = new ZigIndicator();
		// 过细,将无法分出波,过大找的波较少,对于价来说, 3-3.3为合适
		zigInd.setThreshold( (double)3.2 );
		zigInd.setIndicatorModel( klineStkIndiModel );

		// --- use one point value check ---
		Map<String, java.io.Serializable > resultMap  = zigInd.calculate();

		List<CoordinatePoint> points = new Vector<CoordinatePoint>();
		
		// --- 找出波谷 ---
		List<ZigIndicatorResultItem> troughs = (List<ZigIndicatorResultItem>) resultMap.get( ZigIndicator.ALL_CREST );		
		for (ZigIndicatorResultItem item : troughs) {
			DailyKLineStock kline = (DailyKLineStock)item.getAssoRef();
			OriginalDataPoint dataPoint = new KLineLowOriginalDataPoint(kline);
			CoordinatePoint refPoint = context.transformToCoordinatePoint(dataPoint);
			//System.out.println("...... " + kline.getDate() + " , " + refPoint.getXvalue() + " , " + refPoint.getYvalue());
			points.add(refPoint);
		}
		
		return points;
		
	}
	
	
	private List<ShapeEquation> mergeTopSameLine(List<AbstractLineEquation> shapeEquationsList) {
		
		// --- sort by value ---
		Collections.sort( shapeEquationsList , new SimpleAbstractLineEquationComparator() );
		
		// --- 找出一定模糊的数据 ---
		AbstractLineEquation compared = null;
		
		
		List<ShapeEquation> resultLines = new Vector<ShapeEquation>();
		
		List<AbstractLineEquation> tmpGroup = new Vector<AbstractLineEquation>();
		
		for (Iterator<AbstractLineEquation> outerIter = shapeEquationsList.iterator() ; outerIter.hasNext();  ) {
			compared = outerIter.next();
			double aCompared = compared.getCoefficientA();
			double bCompared = compared.getCoefficientB();
			// --- add the line first
			tmpGroup.add( compared );
			outerIter.remove();
			
			for (Iterator<AbstractLineEquation> innerIter = shapeEquationsList.iterator() ; innerIter.hasNext();  ) {
				AbstractLineEquation inner = innerIter.next();
				// --- 分析关联的连线
				boolean comparedResult = Math.abs( inner.getCoefficientB() - bCompared ) < 0.3;
				comparedResult = comparedResult && Math.abs( inner.getCoefficientA() - aCompared ) < 0.012;
				if ( comparedResult ) {
					tmpGroup.add( inner );
				}
			}
			
			// ---- check the group line ---
			if ( tmpGroup.size() > 1 ) {
				int count = 0;
				double aSum = 0;
				double bSum = 0;
				AbstractLineEquation line = null;
				// --- count value ---
				
				for (int i = 0 ; i < tmpGroup.size() ; i++) {
					line = tmpGroup.get(i);
					count++;
					aSum = aSum + line.getCoefficientA();
					bSum = bSum + line.getCoefficientB();
				}

				
				double avgA = aSum /count;
				double avgB = bSum / count;
				
				// --- build the line ---
				FocusLineEquation focusle = new FocusLineEquation();
				focusle.setCoefficientA(avgA);
				focusle.setCoefficientB(avgB);
				
				resultLines.add( focusle );
			}
			
			tmpGroup.clear();
		}


		return resultLines;
	}
	

	private class SimpleAbstractLineEquationComparator implements Comparator<AbstractLineEquation> {

		@Override
		public int compare(AbstractLineEquation arg0, AbstractLineEquation arg1) {
			
			double compYValue1 = arg0.getCoefficientB();
			double compYValue2 = arg1.getCoefficientB();
			
			int result = 0;
			if ( compYValue1 > compYValue2) {
				result = 1;
			}
			else if ( compYValue1 < compYValue2) {
				result = -1;
			}


			return result;
		}
		
	}
	
	
	
}
